package com.mp.approvalreq.util;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.mp.approvalreq.entity.*;
import com.mp.approvalreq.entity.common.Constants;
import com.mp.approvalreq.entity.dto.RequestInfoDTO;
import com.mp.approvalreq.entity.dto.TemplateDTO;
import com.mp.approvalreq.entity.po.ComponentGroup;
import com.mp.auth.entity.Auth;
import com.mp.auth.service.ReadServicePrx;
import com.mp.user.entity.User;
import com.mp.user.util.UserUtils;
import com.plusmoney.exception.RpcServerLogicalException;
import com.plusmoney.util.Utils;
import com.qq.tars.client.util.ServantUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigDecimal;
import java.util.*;

/**
 * 审批工具类
 */
public class ApprovalUtils {

    private static final Logger logger = LoggerFactory.getLogger(ApprovalUtils.class);

    private static final List<Integer> TEST_COMPANY_ID = Arrays.asList(1829, 1992, 4682);

    public static boolean isApprovalAdmin(User user) {
        if (UserUtils.isAdmin(user)) {
            return true;
        }
        logger.info("判断管理员:{}", JSONObject.toJSONString(user));
        try {
            ReadServicePrx readServicePrx = ServantUtils.getObject(ReadServicePrx.class);
            Auth auth = new Auth();
            auth.setAuthType(22);
            auth.setCompanyId(user.getCompanyId());
            Auth result = readServicePrx.getContactidsByAuthType(user, auth);
            List<Integer> contactIds = Utils.string2list(result.getContactIds());
            return contactIds.contains(user.getContactId());
        } catch (Throwable throwable) {
            // 2020年3月17日 17:05:14
            EmailUtils.sendMail("判断审批管理员出错", throwable);
            logger.error(throwable.getMessage(), throwable);
            return true;
        }
    }


    public static String getTemplateDefaultName(Integer templateType) {
        String name = "";
        switch (templateType) {
            case Template.EXPENSES:
                name = "报销";
                break;
            case Template.LEAVE:
                name = "请假";
                break;
            case Template.OUTDOOR:
                name = "外出";
                break;
            case Template.PURCHASE:
                name = "申购";
                break;
            case Template.APPEND_SIGN:
                name = "补打卡";
                break;
            case Template.OTHER:
                name = "自定义模板";
                break;
            case Template.BUSINESS_TRIP:
                name = "出差";
                break;
            case Template.COMPENSATORY_LEAVE:
                name = "补假";
                break;
            case Template.WORK_OVERTIME:
                name = "加班";
                break;
            case Template.DAYS_OFF:
                name = "调休";
                break;
            default:
                break;
        }
        return name;
    }


    /**
     * 是否是指定某些人可用的适用范围
     *
     * @param departmentIds
     * @return
     */
    public static boolean isSpecificRange(String departmentIds) {
        return Objects.equals(departmentIds, "-1");
    }


    /**
     * 是否是指定部门和指定人可用
     *
     * @param departmentIds
     * @return
     */
    public static boolean isSpecifiedDepts(String departmentIds) {
        return !isAllCompanyRange(departmentIds) && !isSpecificRange(departmentIds);
    }


    /**
     * 是否是全公司的适用范围
     *
     * @param departmentIds
     * @return
     */
    public static boolean isAllCompanyRange(String departmentIds) {
        return Objects.equals(departmentIds, "0");
    }


    /**
     * 判断审批类型是否是多模板互斥
     *
     * @param templateType
     * @return
     */
    public static boolean isMoreTemplateType(Integer templateType) {
        return templateType == Template.APPEND_SIGN
                || templateType == Template.COMPENSATORY_LEAVE
                || templateType == Template.WORK_OVERTIME;
    }


    /**
     * 判断是否是调休请假
     *
     * @param components
     * @return
     */
    public static boolean isWorkDaysOffRequest(List<TemplateComponent> components) {
        for (TemplateComponent component : components) {
            if (component.getNum() == 3 && component.getType() == ContentType.SINGLE_CHOSEN) {
                if ("调休".equals(component.getValue())) {
                    return true;
                }
            }
        }
        return false;
    }


    /**
     * 设置审批的支出金额
     *
     * @param requestInfoDTOS
     * @param componentMap
     * @param templateDTOS
     */
    public static void setApprovalsCostMoney(List<RequestInfoDTO> requestInfoDTOS,
                                             Map<Integer, List<TemplateComponent>> componentMap, List<TemplateDTO> templateDTOS) {
        for (RequestInfoDTO requestInfoDTO : requestInfoDTOS) {
            BigDecimal requestCost = BigDecimal.ZERO;

            if (requestInfoDTO.getDefaultType() == Template.EXPENSES) {
                if (StringUtils.isNotEmpty(requestInfoDTO.getTotalMoney())) {
                    requestCost = requestCost.add(new BigDecimal(requestInfoDTO.getTotalMoney()));
                    requestInfoDTO.setCostMoney(requestCost);
                    continue;
                }
            }

            List<TemplateComponent> components = componentMap.get(requestInfoDTO.getRequestId());
            TemplateDTO templateDTO = getTemplateDTO(requestInfoDTO.getTemplateId(), templateDTOS);

            assert templateDTO != null;
            requestCost = getBigDecimal(requestCost, components, templateDTO);
            requestInfoDTO.setCostMoney(requestCost);
        }
    }

    private static BigDecimal getBigDecimal(BigDecimal reqeustCost, List<TemplateComponent> components, TemplateDTO templateDTO) {
        if (StringUtils.isNotEmpty(templateDTO.getRelateAnalysisNum())) {
            int num = Integer.parseInt(templateDTO.getRelateAnalysisNum().trim());
            for (TemplateComponent component : components) {
                if (component.getNum() == num
                        && component.getType() == ContentType.MONEY
                        && StringUtils.isNotEmpty(component.getValue())) {
                    reqeustCost = reqeustCost.add(new BigDecimal(component.getValue()));

                }
            }
        } else {
            for (TemplateComponent component : components) {
                if (component.getType() == ContentType.MONEY
                        && StringUtils.isNotEmpty(component.getValue())) {
                    reqeustCost = reqeustCost.add(new BigDecimal(component.getValue()));
                }
            }
        }
        return reqeustCost;
    }

    private static TemplateDTO getTemplateDTO(Integer templateId, List<TemplateDTO> templateDTOS) {
        for (TemplateDTO templateDTO : templateDTOS) {
            if (templateDTO.getTemplateId().equals(templateId)) {
                return templateDTO;
            }
        }
        return null;
    }


    public static int getEndTimeNum(int templateType) {
        int num = 0;
        if (templateType == Template.LEAVE
                || templateType == Template.OUTDOOR
                || templateType == Template.COMPENSATORY_LEAVE
                || templateType == Template.WORK_OVERTIME) {
            num = 2;
        } else if (templateType == Template.DAYS_OFF) {
            num = 3;
        } else if (templateType == Template.BUSINESS_TRIP) {
            num = 7;
        }
        return num;
    }


    /**
     * 从组件列表中获取审批的请假、外出、出差的开始时间、结束时间
     */
    public static List<String> getTimeList(List<TemplateComponent> list, int defaultType) {
        List<String> times = new LinkedList<>();
        String startTime = null;
        String endTime = null;

        for (TemplateComponent tc : list) {
            if (defaultType == Template.LEAVE
                    || defaultType == Template.OUTDOOR
                    || defaultType == Template.COMPENSATORY_LEAVE
                    || defaultType == Template.WORK_OVERTIME) {                // 请假/外出/补假/加班
                if (tc.getNum() == 1) {
                    startTime = tc.getValue();
                }
                if (tc.getNum() == 2) {
                    endTime = tc.getValue();
                }
            }

            if (defaultType == Template.DAYS_OFF) {                             // 调休
                if (tc.getNum() == 2) {
                    startTime = tc.getValue();
                }
                if (tc.getNum() == 3) {
                    endTime = tc.getValue();
                }
            }

            if (defaultType == Template.BUSINESS_TRIP) {                            // 出差模板的时间组件:6,7
                if (tc.getNum() == 6) {
                    startTime = tc.getValue();
                }
                if (tc.getNum() == 7) {
                    endTime = tc.getValue();
                }
            }
        }

        times.add(startTime);
        times.add(endTime);
        return times;
    }


    /**
     * 判断当前用户的generation是否可以提交审批
     *
     * @param request
     * @param template
     */
    public static void checkGeneration(Request request, Template template) {
        int defaultType = template.getDefaultType();

        if (ApprovalUtils.checkNotAuthGeneration(request.getGeneration(), template.getTemplateGeneration())) {
            throw new RpcServerLogicalException(1, "请更新大管加版本");
        }

        // 加班审批只有generation >=3 的版本才能使用
        if (defaultType == Template.WORK_OVERTIME) {
            if (Utils.isNotNull(request.getGeneration()) && request.getGeneration() < 3) {
                throw new RpcServerLogicalException(1, "请更新大管加版本");
            }
        }

        // 新版补打卡,只允许generation >= 2的版本使用
        if (defaultType == Template.APPEND_SIGN) {
            if (Utils.isNotNull(request.getGeneration()) && request.getGeneration() < 2) {
                throw new RpcServerLogicalException(1, "请更新大管加版本");
            }
        }
    }

    /**
     * 判断用户的generation是否 大于等于 模板或审批generation
     *
     * @param userGeneration
     * @param requestGeneration
     * @return
     */
    public static boolean checkNotAuthGeneration(Integer userGeneration, Integer requestGeneration) {
        // 模板版本从4开始计算
        userGeneration = Utils.isNull(userGeneration) ? 0 : userGeneration;
        requestGeneration = Utils.isNull(requestGeneration) ? 0 : requestGeneration;
        return requestGeneration >= Constants.DEFAULT_GENERATION && userGeneration < requestGeneration;
    }


    /**
     * 老版本查看新版本的补打卡审批 则提示用户更新
     *
     * @param request
     * @param generation
     */
    public static void isNewCheckInGeneration(Request request, int generation) {
        if (request.getDefaultType() == Template.APPEND_SIGN) {

            boolean isNewCheckInTemplate = false;

            List<TemplateComponent> templateComponents = request.getComponentsContent();
            for (TemplateComponent component : templateComponents) {
                // 新版本的补打卡
                if (component.getNum() == 1 && "缺卡时间".equals(component.getName())) {
                    isNewCheckInTemplate = true;
                    break;
                }
            }

            if (isNewCheckInTemplate && generation < 2) {
                throw new RpcServerLogicalException(1, "请更新大管加版本");
            }
        }
    }


    /**
     * 替换新版本的报销审批的数据,提示用户更新
     * 新版本的查看审批时,会传generation这个字段用于标识;老版本则没有
     *
     * @param request
     * @param generation
     * @return
     */
    public static void replaceNewExpenseValue(Request request, int generation) {
        if (request.getDefaultType() == Template.EXPENSES) {
            // 新版报销版本的数据,(根据报销总额是否为Null进行判断)
            if (request.getTotalMoney() != null && generation == 0) {
                List<TemplateComponent> tcList = request.getComponentsContent();
                for (TemplateComponent tc : tcList) {
                    if (tc.getNum() == 1 && tc.getType() == ContentType.SINGLE_LINE) {
                        tc.setValue("报销包含多明细，请升级大管加版本");
                    }

                    if (tc.getNum() == 2 && tc.getType() == ContentType.MONEY) {
                        tc.setValue(request.getTotalMoney());
                    }

                    if (tc.getNum() == 3 && tc.getType() == ContentType.DATE) {
                        JSONArray arr = JSON.parseArray(tc.getValue());
                        tc.setValue(arr.getString(0));
                    }
                }
                request.setComponentsContentsStr(JSON.toJSONString(tcList));
            }
        }
    }


    /**
     * Hack: 在列表上将新版本提交的报销数据,替换成老版本也能显示的数据格式,防止前端崩溃,等所有客户都更新版本后就可以去掉了
     * android: 3.0.9支持
     * ios:3.0.6 支持
     *
     * @param requests
     */
    public static void replaceNewExpenseValue(List<Request> requests) {
        if (Utils.isEmpty(requests)) {
            return;
        }

        for (Request request : requests) {
            if (Utils.isEmpty(request.getComponentsContent()) || StringUtils.isEmpty(request.getTemplateComponent())) {
                return;
            }
            if (request.getDefaultType() == Template.EXPENSES) {
                // 新版本报销模板数据
                if (request.getTotalMoney() != null) {
                    String str = request.getTemplateComponent();
                    List<TemplateComponent> templateComponents = JSONObject.parseArray(str, TemplateComponent.class);
                    for (TemplateComponent tc : templateComponents) {
                        if (tc.getNum() == 1 && tc.getType() == ContentType.SINGLE_LINE) {
                            JSONArray arr = JSON.parseArray(tc.getValue());
                            if (arr.size() == 1) {
                                tc.setValue(arr.getString(0));
                            } else {
                                tc.setValue(arr.getString(0) + "等");
                            }
                        }

                        if (tc.getNum() == 2 && tc.getType() == ContentType.MONEY) {
                            tc.setValue(request.getTotalMoney());
                        }

                        if (tc.getNum() == 3 && tc.getType() == ContentType.DATE) {
                            JSONArray arr = JSON.parseArray(tc.getValue());
                            tc.setValue(arr.getString(0));
                        }
                    }
                    request.setTemplateComponent(JSON.toJSONString(templateComponents));
                    request.setComponentsContent(templateComponents);
                }
            }
        }
    }


    public static List<Integer> getRequestIds(List<RequestInfoDTO> requestInfoDTOS) {
        List<Integer> requestIds = new ArrayList<>(requestInfoDTOS.size());

        for (RequestInfoDTO requestInfoDTO : requestInfoDTOS) {
            requestIds.add(requestInfoDTO.getRequestId());
        }

        return requestIds;
    }


    public static Map<Integer, User> getUserMap(List<User> users) {
        Map<Integer, User> userMap = new HashMap<>();

        for (User user : users) {
            userMap.put(user.getContactId(), user);
        }

        return userMap;
    }


    public static List<User> getUsers(Map<Integer, User> userMap, String contactIds) {
        List<User> users = new ArrayList<>();

        if (StringUtils.isEmpty(contactIds)) {
            return users;
        }

        for (String contactId : contactIds.split(",")) {
            users.add(userMap.get(Integer.valueOf(contactId)));
        }

        return users;
    }

    public static String getUsersContactName(List<User> users) {
        List<String> contactNames = new ArrayList<>(users.size());

        for (User user : users) {
            contactNames.add(user.getContactName());
        }

        return ListHelper.list2string(contactNames);
    }


    /**
     * 从模板中获取关联的组件集ids
     *
     * @param componentGroupJsonStr --> [ {"num":xx, "id":xx}, {"num":xx, "id":xx}, {"num":xx, "id":xx} ]
     * @return
     */
    public static String getComponentGroupIds(String componentGroupJsonStr) {
        if (StringUtils.isEmpty(componentGroupJsonStr)) {
            return null;
        }

        List<Integer> list = new ArrayList<>();
        JSONArray jsonArray = JSONArray.parseArray(componentGroupJsonStr);
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject object = jsonArray.getJSONObject(i);
            list.add(object.getInteger("id"));
        }

        return ListHelper.list2string(list);
    }


    /**
     * 为模板中组件集设置组件的num
     *
     * @param componentGroupJsonStr
     * @param componentGroups
     */
    public static void setComponentGroupNum(String componentGroupJsonStr, List<ComponentGroup> componentGroups) {
        List<ComponentGroup> templateComponentGroups = JSONObject.parseArray(componentGroupJsonStr, ComponentGroup.class);
        for (ComponentGroup templateComponentGroup : templateComponentGroups) {
            // 注意: 不允许在一个模板中出现重复的组件集,即一个模板中,一个组件集id只会出现一次
            for (ComponentGroup componentGroup : componentGroups) {
                if (componentGroup.getId().equals(templateComponentGroup.getId())) {
                    componentGroup.setNum(templateComponentGroup.getNum());
                }
            }
        }
    }

    public static DaysOffTimeInfo getDaysOffTimeInfo(Map<Integer, TemplateComponent> componentMap) {
        TemplateComponent component = componentMap.get(4);
        if (Utils.isNull(component)) {
            throw new RpcServerLogicalException(1, "调休时长不能为空");
        }
        if (StringUtils.isEmpty(component.getValue())) {
            throw new RpcServerLogicalException(1, "调休时长不能为空");
        }
        return JSONObject.parseObject(component.getValue(), DaysOffTimeInfo.class);
    }

    public static boolean isTestCompany(Integer companyId) {
        return TEST_COMPANY_ID.contains(companyId);
    }

    public static boolean isTestWorkTrend(Integer companyId) {
        return Objects.equals(companyId, 12) || TEST_COMPANY_ID.contains(companyId);
    }
}
